import psutil
import subprocess
import json
import os
from datetime import datetime
import logging
import time
import threading

class ProcessManager:
    def __init__(self):
        self.processes = {}
        self.monitor_thread = None
        self.is_monitoring = False
        self.lock = threading.Lock()
        self.config_file = 'process_config.json'
        self.logger = self._setup_logger()
        self.load_config()

    def _setup_logger(self):
        logger = logging.getLogger('ProcessManager')
        logger.setLevel(logging.INFO)
        handler = logging.FileHandler('process_manager.log')
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    def save_config(self):
        """保存进程配置到文件"""
        config = {
            'processes': self.processes,
            'last_updated': datetime.now().isoformat()
        }
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
            self.logger.info("Configuration saved successfully")
        except Exception as e:
            self.logger.error(f"Failed to save configuration: {str(e)}")

    def load_config(self):
        """从文件加载进程配置"""
        if not os.path.exists(self.config_file):
            return

        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
                self.processes = config.get('processes', {})
            self.logger.info("Configuration loaded successfully")
        except Exception as e:
            self.logger.error(f"Failed to load configuration: {str(e)}")

    def is_process_running(self, name, command):
        """检查进程是否已经在运行"""
        # 检查是否在监控列表中
        if name in self.processes:
            try:
                pid = self.processes[name]['pid']
                process = psutil.Process(pid)
                if process.is_running():
                    return True, f"进程 {name} 已经在运行中"
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                pass

        # 检查系统中是否有同名进程在运行
        for proc in psutil.process_iter(['pid', 'name', 'exe', 'cmdline']):
            try:
                process_info = proc.info
                if process_info['name'].lower() == name.lower():
                    # 检查命令行是否匹配
                    cmdline = ' '.join(process_info['cmdline']) if process_info['cmdline'] else ''
                    if command.lower() in cmdline.lower():
                        return True, f"发现同名进程 {name} 正在运行"
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                continue

        return False, None

    def get_running_processes(self):
        """获取所有正在运行的进程信息"""
        running_processes = []
        for proc in psutil.process_iter(['pid', 'name', 'exe', 'cmdline']):
            try:
                process_info = proc.info
                if process_info['exe']:  # 只包含有可执行文件路径的进程
                    running_processes.append({
                        'pid': process_info['pid'],
                        'name': process_info['name'],
                        'exe': process_info['exe'],
                        'cmdline': ' '.join(process_info['cmdline']) if process_info['cmdline'] else '',
                        'is_monitored': process_info['pid'] in [p['pid'] for p in self.processes.values()]
                    })
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass
        return running_processes

    def add_existing_process(self, pid):
        """添加一个已存在的进程到监控列表"""
        try:
            process = psutil.Process(pid)
            name = process.name()
            exe = process.exe()
            
            # 检查进程是否已经在监控列表中
            for monitored_pid in [p['pid'] for p in self.processes.values()]:
                if monitored_pid == pid:
                    return False, "进程已经在监控列表中"
            
            self.processes[name] = {
                'pid': pid,
                'command': exe,
                'start_time': datetime.fromtimestamp(process.create_time()).isoformat(),
                'status': 'running'
            }
            self.save_config()  # 保存配置
            self.logger.info(f"Added existing process {name} with PID {pid}")
            return True, "进程添加成功"
        except Exception as e:
            self.logger.error(f"Failed to add existing process {pid}: {str(e)}")
            return False, f"添加进程失败: {str(e)}"

    def _resolve_path(self, path):
        """解析文件路径，支持相对路径"""
        # 如果是绝对路径，直接返回
        if os.path.isabs(path):
            return path
        
        # 尝试在当前目录查找
        current_dir = os.getcwd()
        full_path = os.path.join(current_dir, path)
        if os.path.exists(full_path):
            return full_path
            
        # 尝试在系统PATH中查找
        for dir_path in os.environ["PATH"].split(os.pathsep):
            full_path = os.path.join(dir_path, path)
            if os.path.exists(full_path):
                return full_path
                
        return path  # 如果都找不到，返回原始路径

    def start_process(self, name, command):
        """启动新进程"""
        with self.lock:
            # 检查进程是否已存在
            if name in self.processes:
                return False, f"进程 {name} 已存在"

            try:
                # 解析文件路径
                full_path = self._resolve_path(command)
                
                # 检查文件是否存在
                if not os.path.exists(full_path):
                    return False, f"可执行文件 {command} 不存在"

                # 启动进程
                process = subprocess.Popen(full_path, shell=True)
                self.processes[name] = {
                    'pid': process.pid,
                    'command': full_path,
                    'start_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'status': 'running'
                }
                self.save_config()  # 保存配置
                return True, f"进程 {name} 已启动"
            except Exception as e:
                logging.error(f"启动进程 {name} 时发生错误: {str(e)}")
                return False, f"启动进程失败: {str(e)}"

    def stop_process(self, name):
        """停止进程"""
        with self.lock:
            if name not in self.processes:
                return False, f"进程 {name} 不存在"

            try:
                pid = self.processes[name]['pid']
                try:
                    process = psutil.Process(pid)
                    # 尝试正常终止进程
                    process.terminate()
                    try:
                        process.wait(timeout=3)  # 等待3秒
                    except psutil.TimeoutExpired:
                        # 如果进程没有及时终止，强制结束
                        process.kill()
                        process.wait(timeout=1)
                except psutil.NoSuchProcess:
                    # 进程已经不存在
                    pass
                except Exception as e:
                    logging.error(f"停止进程 {name} 时发生错误: {str(e)}")
                    return False, f"停止进程失败: {str(e)}"
                finally:
                    # 从监控列表中移除
                    del self.processes[name]
                    self.save_config()  # 保存配置
                    return True, f"进程 {name} 已停止"
            except Exception as e:
                logging.error(f"停止进程 {name} 时发生错误: {str(e)}")
                return False, f"停止进程失败: {str(e)}"

    def check_processes(self):
        """检查所有进程状态"""
        with self.lock:
            for name, info in list(self.processes.items()):
                try:
                    if not self._is_process_running(info['pid']):
                        logging.info(f"进程 {name} 已停止，尝试重启")
                        self._restart_process(name, info['command'])
                except Exception as e:
                    logging.error(f"检查进程 {name} 时发生错误: {str(e)}")

    def _is_process_running(self, pid):
        """检查进程是否在运行"""
        try:
            process = psutil.Process(pid)
            return process.is_running() and process.status() != psutil.STATUS_ZOMBIE
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            return False

    def _restart_process(self, name, command):
        """重启进程"""
        try:
            # 移除旧的进程记录
            if name in self.processes:
                del self.processes[name]

            # 解析文件路径
            full_path = self._resolve_path(command)
            
            # 启动新进程
            process = subprocess.Popen(full_path, shell=True)
            self.processes[name] = {
                'pid': process.pid,
                'command': full_path,
                'start_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'status': 'running'
            }
            self.save_config()  # 保存配置
            logging.info(f"进程 {name} 已重启")
        except Exception as e:
            logging.error(f"重启进程 {name} 时发生错误: {str(e)}")

    def start_monitoring(self):
        """启动监控线程"""
        if self.monitor_thread is None or not self.monitor_thread.is_alive():
            self.is_monitoring = True
            self.monitor_thread = threading.Thread(target=self._monitor_processes)
            self.monitor_thread.daemon = True
            self.monitor_thread.start()

    def _monitor_processes(self):
        """监控进程状态"""
        while self.is_monitoring:
            try:
                self.check_processes()
                time.sleep(5)  # 每5秒检查一次
            except Exception as e:
                logging.error(f"监控进程时发生错误: {str(e)}")
                time.sleep(5)

    def get_all_processes(self):
        """获取所有进程信息"""
        with self.lock:
            result = []
            for name, info in self.processes.items():
                try:
                    process = psutil.Process(info['pid'])
                    status = 'running' if process.is_running() else 'stopped'
                    cpu_percent = process.cpu_percent() if status == 'running' else 0
                    memory_info = process.memory_info() if status == 'running' else None
                    memory_percent = process.memory_percent() if status == 'running' else 0

                    result.append({
                        'name': name,
                        'pid': info['pid'],
                        'command': info['command'],
                        'start_time': info['start_time'],
                        'status': status,
                        'cpu_percent': cpu_percent,
                        'memory_percent': memory_percent,
                        'memory_used': memory_info.rss if memory_info else 0
                    })
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    result.append({
                        'name': name,
                        'pid': info['pid'],
                        'command': info['command'],
                        'start_time': info['start_time'],
                        'status': 'stopped',
                        'cpu_percent': 0,
                        'memory_percent': 0,
                        'memory_used': 0
                    })
            return result

    def restart_process(self, name):
        """重启进程"""
        if name not in self.processes:
            return False, f"进程 {name} 不存在"

        try:
            # 先停止进程
            self.stop_process(name)
            # 重新启动进程
            command = self.processes[name]['command']
            process = subprocess.Popen(command, shell=True)
            self.processes[name] = {
                'pid': process.pid,
                'command': command,
                'start_time': datetime.now().isoformat()
            }
            self.save_config()
            return True, f"进程 {name} 重启成功"
        except Exception as e:
            return False, f"重启进程失败: {str(e)}"

    def remove_process(self, name):
        """取消监控进程"""
        with self.lock:
            if name not in self.processes:
                return False, f"进程 {name} 不存在"

            try:
                # 先尝试停止进程
                pid = self.processes[name]['pid']
                try:
                    process = psutil.Process(pid)
                    if process.is_running():
                        process.terminate()
                        try:
                            process.wait(timeout=3)
                        except psutil.TimeoutExpired:
                            process.kill()
                            process.wait(timeout=1)
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    pass  # 进程已经不存在，继续移除监控
                except Exception as e:
                    logging.error(f"停止进程 {name} 时发生错误: {str(e)}")
                    # 即使停止失败，也继续移除监控
                
                # 从监控列表中移除
                del self.processes[name]
                self.save_config()  # 保存配置
                return True, f"已取消监控进程 {name}"
            except Exception as e:
                logging.error(f"取消监控进程 {name} 时发生错误: {str(e)}")
                return False, f"取消监控失败: {str(e)}" 